using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SilkSharp.src
{
	/*
	 * Limit, stabilize, convert and quantize NLSFs.
	 *
	 * @author Dingxin Xu
	 */
	public class Silk_process_NLSFs_FLP
	{
		/*
		 * Limit, stabilize, convert and quantize NLSFs.
		 * @param psEnc Encoder state FLP
		 * @param psEncCtrl Encoder control FLP
		 * @param pNLSF NLSFs (quantized output)
		 */
		static void SKP_Silk_process_NLSFs_FLP(
			SKP_Silk_encoder_state_FLP psEnc,             /* I/O  Encoder state FLP                       */
			SKP_Silk_encoder_control_FLP psEncCtrl,         /* I/O  Encoder control FLP                     */
			float[] pNLSF              /* I/O  NLSFs (quantized output)                */
		)
		{
			bool doInterpolate;
			float[] pNLSFW = new float[ Silk_define.MAX_LPC_ORDER ];
			float NLSF_mu, NLSF_mu_fluc_red, i_sqr, NLSF_interpolation_factor = 0.0f;
			SKP_Silk_NLSF_CB_FLP psNLSF_CB_FLP;


			/* Used only for NLSF interpolation */
			float[] pNLSF0_temp = new float[ Silk_define.MAX_LPC_ORDER ];
			float[] pNLSFW0_temp = new float[ Silk_define.MAX_LPC_ORDER ];
			int i;

			// assert( psEncCtrl.sCmn.sigtype == Silk_define.SIG_TYPE_VOICED || psEncCtrl.sCmn.sigtype == Silk_define.SIG_TYPE_UNVOICED );

			/***********************/
			/* Calculate mu values */
			/***********************/
			if( psEncCtrl.sCmn.sigtype == Silk_define.SIG_TYPE_VOICED )
			{
				NLSF_mu = 0.002f - 0.001f * psEnc.speech_activity;
				NLSF_mu_fluc_red = 0.1f - 0.05f * psEnc.speech_activity;
			}
			else
			{
				NLSF_mu = 0.005f - 0.004f * psEnc.speech_activity;
				NLSF_mu_fluc_red = 0.2f - 0.1f * ( psEnc.speech_activity + psEncCtrl.sparseness );
			}

			/* Calculate NLSF weights */
			Silk_NLSF_VQ_weights_laroia_FLP.SKP_Silk_NLSF_VQ_weights_laroia_FLP( pNLSFW, pNLSF, psEnc.sCmn.predictLPCOrder );

			/* Update NLSF weights for interpolated NLSFs */
			doInterpolate = ( psEnc.sCmn.useInterpolatedNLSFs == 1 ) && ( psEncCtrl.sCmn.NLSFInterpCoef_Q2 < ( 1 << 2 ) );
			if( doInterpolate )
			{

				/* Calculate the interpolated NLSF vector for the first half */
				NLSF_interpolation_factor = 0.25f * psEncCtrl.sCmn.NLSFInterpCoef_Q2;
				Silk_wrappers_FLP.SKP_Silk_interpolate_wrapper_FLP( pNLSF0_temp, psEnc.sPred.prev_NLSFq, pNLSF,
					NLSF_interpolation_factor, psEnc.sCmn.predictLPCOrder );

				/* Calculate first half NLSF weights for the interpolated NLSFs */
				Silk_NLSF_VQ_weights_laroia_FLP.SKP_Silk_NLSF_VQ_weights_laroia_FLP( pNLSFW0_temp, pNLSF0_temp, psEnc.sCmn.predictLPCOrder );

				/* Update NLSF weights with contribution from first half */
				i_sqr = NLSF_interpolation_factor * NLSF_interpolation_factor;
				for( i = 0; i < psEnc.sCmn.predictLPCOrder; i++ )
				{
					pNLSFW[ i ] = 0.5f * ( pNLSFW[ i ] + i_sqr * pNLSFW0_temp[ i ] );
				}
			}

			/* Set pointer to the NLSF codebook for the current signal type and LPC order */
			psNLSF_CB_FLP = psEnc.psNLSF_CB_FLP[ psEncCtrl.sCmn.sigtype ];

			/* Quantize NLSF parameters given the trained NLSF codebooks */
			Silk_NLSF_MSVQ_encode_FLP.SKP_Silk_NLSF_MSVQ_encode_FLP( psEncCtrl.sCmn.NLSFIndices, pNLSF, psNLSF_CB_FLP, psEnc.sPred.prev_NLSFq,
					pNLSFW, NLSF_mu, NLSF_mu_fluc_red, psEnc.sCmn.NLSF_MSVQ_Survivors,
					psEnc.sCmn.predictLPCOrder, psEnc.sCmn.first_frame_after_reset );

			/* Convert quantized NLSFs back to LPC coefficients */
			Silk_wrappers_FLP.SKP_Silk_NLSF2A_stable_FLP( psEncCtrl.PredCoef[ 1 ], pNLSF, psEnc.sCmn.predictLPCOrder );

			if( doInterpolate )
			{
				/* Calculate the interpolated, quantized NLSF vector for the first half */
				Silk_wrappers_FLP.SKP_Silk_interpolate_wrapper_FLP( pNLSF0_temp, psEnc.sPred.prev_NLSFq, pNLSF,
					NLSF_interpolation_factor, psEnc.sCmn.predictLPCOrder );

				/* Convert back to LPC coefficients */
				Silk_wrappers_FLP.SKP_Silk_NLSF2A_stable_FLP( psEncCtrl.PredCoef[ 0 ], pNLSF0_temp, psEnc.sCmn.predictLPCOrder );

			}
			else
			{
				/* Copy LPC coefficients for first half from second half */
				System.Array.Copy( psEncCtrl.PredCoef[ 1 ], 0, psEncCtrl.PredCoef[ 0 ], 0, psEnc.sCmn.predictLPCOrder );
			}
		}
	}
}
